package message_service

import (
	"fmt"
	"shimmer/neusoft_club_backend/controllers/utils"
	"shimmer/neusoft_club_backend/dao/domain"
	"shimmer/neusoft_club_backend/services"
	"strings"
)

type SendMessageReq struct {
	Title      string
	Content    string
	ReceiverID *int64
	SenderID   *int64
	ClubID     *int64
	Type       domain.MessageType
	Extra      *map[string]interface{}
}

func SendMessage(sendReq *SendMessageReq) (res *domain.Message, err error) {
	var extra *domain.JSON
	if sendReq.Extra != nil {
		tmp := domain.NewJSON(*sendReq.Extra)
		extra = &tmp
	}
	res = &domain.Message{
		ID:         0,
		SenderID:   sendReq.SenderID,
		ReceiverID: sendReq.ReceiverID,
		ClubID:     sendReq.ClubID,
		Title:      sendReq.Title,
		Content:    sendReq.Content,
		Type:       sendReq.Type,
		Extra:      extra,
	}

	if err = services.DBEngine.Save(res).Error; err != nil {
		return nil, err
	}
	return
}

func FindAllMessagesOfUserReceived(userID int64, where map[string]interface{}, pageQuery *utils.PaginationQuery) (res utils.Pagination, err error) {
	where["receiver_id"] = userID
	return FindAllMessages(where, pageQuery)
}

func FindAllMessagesOfUserSent(userID int64, where map[string]interface{}, pageQuery *utils.PaginationQuery) (res utils.Pagination, err error) {
	where["sender_id"] = userID
	return FindAllMessages(where, pageQuery)
}
func FindAllMessages(where map[string]interface{}, pageQuery *utils.PaginationQuery) (res utils.Pagination, err error) {
	messages := make([]*domain.Message, 0)

	db := services.DBEngine.Joins(domain.MessageFieldReceiver).Joins(domain.MessageFieldSender).Joins(domain.MessageFieldClub)

	db = db.Preload(strings.Join([]string{domain.MessageFieldReceiver, domain.UserFieldAvatar}, "."))
	db = db.Preload(strings.Join([]string{domain.MessageFieldSender, domain.UserFieldAvatar}, "."))
	db = db.Preload(domain.MessageFieldMarkReadList)
	if where["mark_read"] != nil {
		markRead, ok := where["mark_read"].(bool)
		delete(where, "mark_read")
		if ok {
			userReadQuery := services.DBEngine.Model(&domain.MessageRead{}).Where(fmt.Sprintf("message_id = %s.id", domain.MessageTableName))
			if receiverID, ok := where["receiver_id"].(int64); ok {
				userReadQuery = userReadQuery.Where("user_id = ?", receiverID)
			}
			userReadQuery.Select("count(*)")
			if markRead {
				db = db.Where("(?) > 0", userReadQuery)
			} else {
				db = db.Where("(?) = 0", userReadQuery)
			}

		}
	}
	db = services.BuildWhere(where, db)
	return utils.QueryAndPaginate(pageQuery, db, &messages)
}
func FindAllMessagesOfClubThatUsersJoin(userID int64, where map[string]interface{}, pageQuery *utils.PaginationQuery) (res utils.Pagination, err error) {
	messages := make([]*domain.Message, 0)
	actorQuery := services.DBEngine.Model(&domain.UserActor{}).Where("user_id = ? and club_id is not null", userID).Select("club_id")
	clubQuery := services.DBEngine.Model(&domain.Club{}).Where("id in (?)", actorQuery).Select("id")

	db := services.DBEngine.Where("club_id in (?)", clubQuery)
	db = db.Joins(domain.MessageFieldReceiver).Joins(domain.MessageFieldSender).Joins(domain.MessageFieldClub)
	db = db.Preload(strings.Join([]string{domain.MessageFieldReceiver, domain.UserFieldAvatar}, "."))
	db = db.Preload(strings.Join([]string{domain.MessageFieldSender, domain.UserFieldAvatar}, "."))
	db = db.Preload(domain.MessageFieldMarkReadList)
	if where["mark_read"] != nil {
		markRead, ok := where["mark_read"].(bool)
		if ok {
			userReadQuery := services.DBEngine.Model(&domain.MessageRead{}).Where(fmt.Sprintf("message_id = %s.id", domain.MessageTableName))
			if receiverID, ok := where["receiver_id"].(int64); ok {
				userReadQuery = userReadQuery.Where("user_id = ?", receiverID)
			}
			delete(where, "mark_read")
			delete(where, "receiver_id")
			userReadQuery.Select("count(*)")
			if markRead {
				db = db.Where("(?) > 0", userReadQuery)
			} else {
				db = db.Where("(?) = 0", userReadQuery)
			}

		}
	}
	db = services.BuildWhere(where, db)
	return utils.QueryAndPaginate(pageQuery, db, &messages)

}

func FindAllMessagesOfClub(clubID int64, where map[string]interface{}, pageQuery *utils.PaginationQuery) (res utils.Pagination, err error) {
	message := make([]*domain.Message, 0)
	db := services.DBEngine.Where("club_id = ?", clubID)
	db.Joins(domain.MessageFieldClub).Joins(domain.MessageFieldSender)
	db = db.Preload(strings.Join([]string{domain.MessageFieldSender, domain.UserFieldAvatar}, "."))
	db = db.Preload(domain.MessageFieldMarkReadList)
	if where["mark_read"] != nil {
		markRead, ok := where["mark_read"].(bool)
		if ok {
			userReadQuery := services.DBEngine.Model(&domain.MessageRead{}).Where(fmt.Sprintf("message_id = %s.id", domain.MessageTableName))
			if receiverID, ok := where["receiver_id"].(int64); ok {
				userReadQuery = userReadQuery.Where("user_id = ?", receiverID)
			}
			delete(where, "mark_read")
			delete(where, "receiver_id")
			userReadQuery.Select("count(*)")
			if markRead {
				db = db.Where("(?) > 0", userReadQuery)
			} else {
				db = db.Where("(?) = 0", userReadQuery)
			}

		}
	}
	return utils.QueryAndPaginate(pageQuery, db, &message)
}
func MarkMessageAsRead(messageID int64, userID int64) (err error) {
	//err = services.DBEngine.Model(&domain.Message{ID: messageID}).Update("mark_read",true).Error
	read := &domain.MessageRead{MessageID: messageID, UserID: userID}
	err = services.DBEngine.Save(read).Error
	return
}

func FindMessageByID(messageID int64) (res *domain.Message, err error) {
	res = &domain.Message{ID: messageID}
	db := services.DBEngine.Joins(domain.MessageFieldReceiver).Joins(domain.MessageFieldSender).Joins(domain.MessageFieldClub)

	db = db.Preload(strings.Join([]string{domain.MessageFieldReceiver, domain.UserFieldAvatar}, "."))
	db = db.Preload(strings.Join([]string{domain.MessageFieldSender, domain.UserFieldAvatar}, "."))
	db = db.Preload(domain.MessageFieldMarkReadList)
	err = db.First(res).Error
	return
}
func CheckUserCanSend(userID, targetID int64) (res bool, err error) {
	var count int64 = 0
	actorsQuery := services.DBEngine.Model(&domain.UserActor{}).Where("user_id = ? and role >= ?", userID, domain.AuthLeader).Select("club_id")
	clubsQuery := services.DBEngine.Model(&domain.Club{}).Where("id in (?)", actorsQuery).Select("id")
	clubFormsQuery := services.DBEngine.Model(&domain.ClubForm{}).Where("id in (?)", clubsQuery).Select("id")
	subQuery1 := services.DBEngine.Model(&domain.UserApplication{}).Where("form_id in (?)", clubFormsQuery).Select("user_id")
	subQuery2 := services.DBEngine.Model(&domain.UserActor{}).Where("user_id = ? and club_id in (?)", targetID, clubsQuery)
	if err = services.DBEngine.Model(&domain.User{ID: targetID}).Where("id in (?) or id in (?)", subQuery1, subQuery2).Count(&count).Error; err != nil {
		return
	}
	return count > 0, nil
}
